/**
  * @date  2013/05
  * @email colin1124x@gmail.com
*/
(function(ns){
    var instances = {};

    function parse_params(str)
    {
        var re = /\s*([^&:]+)\s*:\s*([^&]*)\s*/g,
             re_boolean = /^(true|false)$/i,
             re_int = /^(0|[1-9]\d*)$/,
             re_float = /^((?:0|[1-9]\d*)(\.\d+)?)$/,
             re_null = /^null$/i;
             
        if (re.test(str)) {
            var params = {};
            str.replace(re, function(s, m1, m2){
                params[m1] = decodeURIComponent(m2);
                (re_boolean.test(params[m1]) && (params[m1] = /true/i.test(params[m1])))
                || (re_int.test(params[m1]) && (params[m1] = parseInt(params[m1], 10)))
                || (re_float.test(params[m1]) && (params[m1] = parseFloat(params[m1], 10)))
                || (re_null.test(params[m1]) && (params[m1] = null));
            });
            
            return params;
        } else {
            
            return decodeURIComponent(str);
        }
    }
    
    function store(command, options)
    {
        options = options || {};
        (options['time'] || 0 == options['time']) && (command += '; max-age=' + options['time']);
        options['path'] && (command += '; path=' + options['path']);
        options['domain'] && (command += '; domain=' + options['domain']);
        options['secure'] && (command += '; secure');
        document.cookie = command;
        return this;
    }

    function Single(name)
    {
        this.name = name;
        this.data = '';
    }
    
    Single.prototype = {
        get: function(){
            
            return this.data;
        },
        set: function(data){
            if ('undefined' != typeof data && 'string' != typeof data && 'number' != typeof data) {
                throw new Error('single mode data must be a string or number');
            }
            this.data = data;
            
            return this;
        },
        del: function(){
            this.data = '';
            return this;
        },
        die: function()
        {
            this.data = '';
            this.store({time: 0});
            return this;
        },
        store: function(options){
            var command = this.name + '=' + this.data;
            store(command, options);
            
            return this;
        }
    };
    
    function Multi(name)
    {
        this.name = name;
        this.data = {};
    }
    
    Multi.prototype = {
        get: function(key){
            if ('undefined' != typeof key) {
                
                return this.data[key];
            }
            
            return this.data;
        },
        set: function(){
            var args = arguments;
            if ('object' == typeof args[0]) {
                for (var k in args[0]) {
                    this.data[k] = args[0][k];
                }
            } else if (('string' == typeof args[0] || 'number' == typeof args[0]) && 'undefined' != typeof args[1]) {
                this.data[args[0]] = args[1];
            } else if ('undefined' != typeof args[0]) {
                throw new Error('args error');
            }

            return this;
        },
        del: function(key){
            delete this.data[key];
            return this;
        },
        die: function()
        {
            this.data = {};
            this.store({time: 0});
            return this;
        },
        store: function(options){
            var vals = [];
            
            for (var key in this.data) {
                vals[vals.length] = key + ':' + encodeURIComponent(this.data[key]);
            }
            
            var command = this.name + '=' + vals.join('&');
            store(command, options);
            
            return this;
        }
    };
    
    function Cookie(name, data)
    {
        name = name || '';
        
        if ( ! (this instanceof Cookie)) {
            
            return new Cookie(name, data);
        } else if ( ! instances[name]) {
            switch (typeof data) {
                case 'string':
                case 'number':
                    instances[name] = new Single(name);
                    break;
                    
                case 'object':
                default:
                    instances[name] = new Multi(name);
            }
        }

        ('undefined' != typeof data) && (instances[name].set(data));

        return instances[name];
    }
    
    Cookie.invoke = function(c)
    {
        for (var name in instances) {
            c.call(instances[name]);
        }
    };

    Cookie.destroy = function(name)
    {
        if ('undefined' == typeof name) {
            Cookie.invoke(Cookie.prototype.die);
            
            return true;
        } else if (instances[name]) {
            instances[name].die();
            
            return true;
        }
        
        return false;
    };

    Cookie.count = function()
    {
        var cnt = 0;
        for (var n in instances) {
            cnt++;
        }
        
        return cnt;
    };

    Cookie.TIME = 'time';
    Cookie.PATH = 'path';
    Cookie.DOMAIN = 'domain';
    Cookie.SECURE = 'secure';

    if ('undefined' != typeof define) {
        define(function(){ return Cookie; });
    }
    
    ns.Cookie = Cookie;
    
    document.cookie.replace(/[^;]+/g, function(m) {
        if ( ! /=/.test(m)) {
            instances[''] = new Cookie('', parse_params(m));
        } else {
            m.replace(/\s*([^=]*)\s*=\s*(.*)\s*/g, function(s, m1, m2) {
                instances[m1] = new Cookie(m1, parse_params(m2));
            });
        }
    });
    
})(this);